from django.contrib.gis.db import models
from django.utils.translation import ugettext_lazy as _
from urllib2 import urlopen
import re
from meta import Agent, Keyword, License 
from time import TimePeriod
from warnings import warn
from mimetypes import guess_type
from duetopia.register.fields import AgentField, KeywordField, ParsedDateField, TimespanField
from duetopia.opensearch import OpenSearch
from django.contrib.gis.models import SpatialRefSys
from django.template import loader, Context

class DataSet(models.Model):
    """
    >>> d = DataSet(name='test',objectType='Raster')
    >>> d.delete(d.id)
    """
    __module__ = 'duetopia.register.models'
    title = models.CharField(max_length=255, blank=True, null=True, verbose_name=_('title'))
    abstract = models.TextField(max_length=16384, null=True, blank=True, verbose_name=_('abstract')) 
    lang = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('language'))
    license =  models.ForeignKey(License,blank=True,null=True,verbose_name=_('language'))
    contacts = AgentField(null=True, blank=True, verbose_name=_('contacts'))
    keywords = KeywordField(blank=True, verbose_name=_('keywords'))
    indexed = ParsedDateField(auto_now_add=True, verbose_name=_('indexed'))
    published = ParsedDateField(null=True, blank=True, verbose_name=_('publication date'))
    updated = ParsedDateField(null=True,blank=True, verbose_name=_('last update date'))
    extents = models.PolygonField(null=True, blank=True,verbose_name=_('extents'))
    timespan = TimespanField(TimePeriod, blank=True, null=True, verbose_name=_('timespan'))
    objects =  models.GeoManager()
    search = OpenSearch()

    class Admin:
        list_display  = ('title', 'abstract', 'pextents');# 'nlayers')
        search_fields = ('title', 'abstract')
        list_per_page = 15;

    class Meta:
        verbose_name = _('data set')
        verbose_name_plural = _('data sets')
        ordering = ('title',)
        
    def __str__(self):
        if self.title:
            if isinstance(self.title, unicode):
                return unicode.encode(self.title, 'utf-8')
            else:
                return str(self.title)
        else:
            return "DataSet(%s)" % (self.id,)

    geometry = "extents"
    def get_kml_url(self):
        return "/duetopia/feature/register/dataset/%s.kml" % self.id
    def pextents(self):
        t = loader.get_template("register/list_map.html")
        return t.render(Context({ "object" : self }))
    pextents.allow_tags = True
    pextents.short_description = _("envelope")
    
    def sources(self):
        try:
            return DataSource.objects.filter(dataset=self)
        except:
            return []            

    def nlayers(self):
        return self.layer_set.count()
    nlayers.short_description = _('layers')

    def get_absolute_url(self):
        return '/duetopia/register/dataset/%s/' % (self.id,)

    def georss_box(self):
        if self.extents is None:
            return None
        else:
            return '%s %s %s %s',(dataset.extents.tuple[0][0][1],dataset.extents.tuple[0][0][0],dataset.extents.tuple[0][2][1],dataset.extents.tuple[0][2][0]) 

class DataType(models.Model):
    __module__ = 'duetopia.register.models'
    name = models.CharField(max_length=64, verbose_name=_('name'), unique=True)
    class Admin:
        list_display = ('name',)
    class Meta:
        verbose_name = _('data type')
        verbose_name_plural = _('data types')
    def __str__(self):
        return self.name

class DataFormat(models.Model):
    """
    ### Return an implementation of a data format. For example,
    ### WMS, ShapeFile, ImageFile, etc.
    >>> fmt = DataFormat.objects.get_or_create(app = 'register', 'WebMappingService')
    >>> m = fmt.get_model()
    >>>
    """
    __module__ = 'duetopia.register.models'
    name = models.CharField(max_length=255, verbose_name=_('name'))
    app = models.CharField(max_length=255, verbose_name=_('application'),default='register',editable=False, null=True)
    model = models.CharField(max_length=255, verbose_name=_('model'),null=True)
    mimetype = models.CharField(max_length=255, unique=True, verbose_name=_('mime type'),null=True,blank=True)
    extension = models.CharField(max_length=8, verbose_name=_('file extension'))
    
    objects = models.GeoManager()

    class Admin:
        list_display = ('name', 'app', 'model')
    class Meta:
        verbose_name = _('data format')
        verbose_name_plural = _('data formats')
    def __str__(self):
        return '%s (%s)' % (self.name, self.mimetype)
    def get_model(self):
        from django.db.models import loading
        try: 
            m = loading.get_model(self.app, self.model)
            return m
        except:
            pass

    #def get_or_create(self, *av, **kw):
    #    if 'name' not in kw:
    #        try:
    #            kw['name'] = 'Unknown ('+kw['mimetype']
    #            return self.create(*av, **kw), True
    #        except:
    #            return self.get_or_create(name='Unknown')    
                    

    def save(self):
        self.get_model()
        super(DataFormat, self).save()

class DataSourceManager(models.GeoManager):
    def get_or_create(self, *av, **kw):
        if 'uri' not in kw:
            raise ValueError('uri is a required kwa for get_or_create')
        try:
            return self.get(uri=kw['uri']), False
        except self.model.DoesNotExist:
            return self.create(*av, **kw), True

    def create(self, *av, **kw):
        if kw['uri'][0] == '/':
            kw['uri'] = 'file://' + kw['uri']
        return super(DataSourceManager, self).create(*av, **kw)

class DataSource(models.Model):
    """
    >>> dataset, created = DataSet.objects.get_or_create(title='NASA JPL')
    >>> format = DataFormat.objects.get(app='register', model='WebMapService')
    >>> uri = 'http://wms.jpl.nasa.gov/wms.cgi'
    >>> DataSource.objects.get_or_create(dataset=dataset, uri=uri, format=format)
    (<DataSource: http://wms.jpl.nasa.gov/wms.cgi>, True)
    >>>
    """
    __module__ = 'duetopia.register.models'
    dataset = models.ForeignKey(DataSet, blank=True, verbose_name=_('data set'))
    uri = models.CharField(max_length=255, unique=True, verbose_name=_('URI'))
    notes = models.TextField(max_length=16384, null=True, blank=True, verbose_name=_('notes'))
 
    format = models.ForeignKey(DataFormat, blank=True, verbose_name=_('format'))
    proj = models.CharField(max_length=255,blank=True,null=True,verbose_name='projection')
    srs = models.ManyToManyField(SpatialRefSys,null=True,blank=True,editable=False, verbose_name=_('spatial reference system'))
    indexed = models.DateTimeField(auto_now_add=True,editable=False)
    updated = ParsedDateField(auto_now_add=True,blank=True, verbose_name=_('last update date'))
    
    timespan = TimespanField(TimePeriod, blank=True, null=True, verbose_name=_('timespan'))
    extents = models.PolygonField(null=True, blank=True,verbose_name=_('extents'))

    objects = DataSourceManager()
    search = OpenSearch()

    class Admin:
        list_display = ('dataset', 'uri', 'format')
    class Meta:
        verbose_name = _('data source')
        verbose_name_plural = _('data sources')
    def __str__(self):
        return self.uri
    def link(self):
        return self.uri
        ### grrr
        if re.match('^http',str(self.uri)):
            # this gets escaped by default, grrr
            return '<a href="'+str(self.uri)+'">'+str(self.uri)+'</a>'
        else:
            return self.uri 

    def source(self):
        # useful for additional sources of metadata - cf wms.py
        model = self.format.get_model()
        if model is None:
            pass
        else:
            src, created = model.objects.get_or_create(source = self)
            return src
    
    def extra(self):
        return self.source()

    def save(self):
    ### make sure we have a format
        mimetype = None
        try:
            self.format

        except DataFormat.DoesNotExist:
            # try to find mimetype, thus format, by other means.
            try:
                if re.match('^http',self.uri):
                    u = urlopen(self.uri)
                    mimetype = u.headers.getheader('Content-Type')
                    mimetype = mimetype.split(';')[0].strip()
                    u.close()
                    (self.format,status) = DataFormat.objects.get_or_create(mimetype=mimetype)
                elif re.match('^file',self.uri) or re.match('^/',self.uri):
                    # file headers magic
                    mime, enc = guess_type(self.uri)
                    if mime is not None:
                        (self.format,status) = DataFormat.objects.get_or_create(mimetype=mime)
                    else:
                        raise ValueError("no known format (unknown file type)")
                else:
                    raise ValueError("no known format (nonexistent file)")# for "+self.uri)
            except:
                # what to do in case we can't figure out anything? -> add dataformat
                raise ValueError("no known format")# for "+self.uri)

        # create a 'empty dataset' if none is already supplied
        if not self.id:
            try: self.dataset
            except DataSet.DoesNotExist:
                print "creating dataset"
                self.dataset = DataSet.objects.create()
        super(DataSource, self).save()
